use secp256k1::{Message, Secp256k1, SecretKey};

use crate::{
    CompactSignatureBytes, PrivateKeyBytes, PublicKeyBytes, PublicKeyHashBytes, TransactionId,
    TransactionValue,
    constants::BLOCK_CHIAN_VERSION,
    script,
    transaction::{Transaction, TransactionIn, TransactionOut, TransactionOutPoint},
};

fn new_tx_out(to: &PublicKeyHashBytes, value: TransactionValue) -> TransactionOut {
    let script_pubkey = script::create_tx_output_script_0(to);
    TransactionOut::new(value, script_pubkey)
}

fn new_tx_in(
    from: &PublicKeyBytes,
    from_priv: &PrivateKeyBytes,
    utxo: &TransactionOutPoint,
) -> TransactionIn {
    let secp = Secp256k1::new();
    let priv_key =
        SecretKey::from_slice(from_priv.as_bytes_ref()).expect("32 bytes, within curve order");

    let message = Message::from_digest(utxo.get_tx_id().as_bytes());
    let payer_sig = secp.sign_ecdsa(&message, &priv_key);
    let payer_sig = payer_sig.serialize_compact();
    let payer_sig = CompactSignatureBytes::new(payer_sig);

    let script_signature = script::create_tx_input_script(payer_sig, from.clone());

    // let sequence = u32::MAX;
    // TransactionIn::new_with_sequence(*utxo, script_signature, sequence)
    TransactionIn::new(*utxo, script_signature)
}

pub fn new_tx(
    from: &PublicKeyBytes,
    from_priv: &PrivateKeyBytes,
    utxo: &TransactionOutPoint,
    to: &PublicKeyHashBytes,
    value: TransactionValue,
) -> Transaction {
    let version = BLOCK_CHIAN_VERSION;
    let lock_time = 0;

    let inputs = vec![new_tx_in(from, from_priv, utxo)];
    let outputs = vec![new_tx_out(to, value)];
    Transaction::new(version, inputs, outputs, lock_time)
}

pub fn new_tx_simple(value: TransactionValue) -> Transaction {
    let version = BLOCK_CHIAN_VERSION;
    let lock_time = 0;

    let from_pub_key_str = "02b97b3c115098f9f258b1fefe70bf5c50efbb051c8b62d5ea65094c043b5b3f34";
    // let from_pub_key_hash_str = "f96249fe9acc612920bb91b42d6c0eddf4b27170";
    let from_priv_key_str = "79209d62d10d0c5e10895a187ecf8a3554f98fa0ace46c10eb9e537eec1a3dee";
    // let to_pub_key_str = "02326ca14e494ae872179b1c8fcdebd1a01cf3ef02e3df0822068d3eafafc61fb0";
    let to_pub_key_hash_str = "7867ffcc47b5bb83d4bdbd04c7980b3b6bc59556";

    let from: PublicKeyBytes = PublicKeyBytes::from_hex_str(from_pub_key_str).unwrap();
    let from_priv: PrivateKeyBytes = PrivateKeyBytes::from_hex_str(from_priv_key_str).unwrap();
    let to: PublicKeyHashBytes = PublicKeyHashBytes::from_hex_str(to_pub_key_hash_str).unwrap();

    #[rustfmt::skip]
    const TX_ID_BYTES: [u8; 32] = [
        1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
        17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
    ];
    let utxo: TransactionOutPoint =
        TransactionOutPoint::new(TransactionId::new(TX_ID_BYTES), 100u32);

    // let inputs = vec![];
    // let outputs = vec![];
    let inputs = vec![new_tx_in(&from, &from_priv, &utxo)];
    let outputs = vec![new_tx_out(&to, value)];
    Transaction::new(version, inputs, outputs, lock_time)
}
